package com.dss.auto_deploy.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dss.auto_deploy.config.WebsocketEndPoint;
import com.dss.auto_deploy.constants.AutoConstants;
import com.dss.auto_deploy.domain.AdmDocker;
import com.dss.auto_deploy.domain.AdmNginx;
import com.dss.auto_deploy.domain.Server;
import com.dss.auto_deploy.dto.AdmNginxAddDto;
import com.dss.auto_deploy.dto.AdmNginxPageDto;
import com.dss.auto_deploy.dto.AdmNginxUpdateDto;
import com.dss.auto_deploy.dto.WsSendDto;
import com.dss.auto_deploy.mapper.AdmDockerMapper;
import com.dss.auto_deploy.mapper.AdmNginxMapper;
import com.dss.auto_deploy.service.IAdmNginxService;
import com.dss.auto_deploy.service.IServerService;
import com.dss.auto_deploy.util.*;
import com.dss.auto_deploy.vo.AdmNginxVo;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.model.Container;
import com.jcraft.jsch.Session;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;


/**
* @Description:nginxService实现类
* @author dongshoushan
* @date 2022-10-30 16:40:11
*/
@Service
@Slf4j
@RequiredArgsConstructor(onConstructor = @_(@Autowired))
public class AdmNginxServiceImpl  extends ServiceImpl<AdmNginxMapper,AdmNginx> implements IAdmNginxService {

    /**
    *
    * nginxMapper
    */
    private final AdmNginxMapper admNginxMapper;
    private final IServerService serverService;
    private final WebsocketEndPoint websocketEndPoint;
    private final DockerUtil dockerUtil;
    private final ThreadPoolTaskExecutor threadPoolTaskExecutor;
    private final RemoteSshUtil remoteSshUtil;
    private final AdmDockerMapper admDockerMapper;
    /**
    * 新增nginx
    * @param admNginxAddDto
    * @return Long
    */
    @Override
    public int insert(AdmNginxAddDto admNginxAddDto){
        AdmNginx admNginx = BeanUtils.copy(admNginxAddDto, AdmNginx.class);
        int insert = admNginxMapper.insert(admNginx);
        if (insert == 1) {
            log.info("新增成功{}",JacksonUtils.toString(admNginx));
        }
        return insert;
    }


    /**
    * 修改nginx
    * @param admNginxUpdateDto
    * @return Long
    */
    @Override
    public int update(AdmNginxUpdateDto admNginxUpdateDto){
        AdmNginx admNginx = BeanUtils.copy(admNginxUpdateDto, AdmNginx.class);
        int number = admNginxMapper.updateById(admNginx);
        if (number == 1) {
            log.info("修改成功{}",JacksonUtils.toString(admNginx));
        }
        return number;
    }


    /**
    * 批量删除nginx
    * @param ids
    * @return Long
    */
    @Override
    public void deleteBatch(Long[] ids){
        this.removeByIds(Arrays.asList(ids));
    }

    /**
    * nginx分页查询
    *
    * @param pageDto
    * @return List<AdmNginx>
    */
    @Override
    public Page<AdmNginxVo> list(AdmNginxPageDto pageDto) throws InterruptedException {
        Page<AdmNginx> tablesPage = new Page<>(pageDto.getPage(), pageDto.getLimit());
        QueryWrapper<AdmNginx> queryWrapper = Wrappers.query();
        if (StringUtils.isNotEmpty(pageDto.getContent())){
            queryWrapper.like("name",pageDto.getContent());
        }
        queryWrapper.orderByAsc("name");
        Page<AdmNginx> pageSelectResult = admNginxMapper.selectPage(tablesPage, queryWrapper);
        List<AdmNginx> records = pageSelectResult.getRecords();
        List<AdmNginxVo> voList = convert(records);
        Page<AdmNginxVo> page = new Page<>();
        page.setRecords(voList);
        page.setTotal(pageSelectResult.getTotal());
        page.setSize(pageSelectResult.getSize()); 
        return page;
    }

    @Override
    public List<AdmNginxVo> convert(List<AdmNginx> list) throws InterruptedException {
        if (list.isEmpty()){
            return new ArrayList<>();
        }
        List<AdmNginxVo> voList = BeanUtils.copyList(list, AdmNginxVo.class);
        List<Long> dockerIds = list.stream().map(AdmNginx::getDockerId).collect(Collectors.toList());
        List<Server> serverList = serverService.getAll();
        List<AdmDocker> dockerList = SpringUtils.getBean(AdmDockerServiceImpl.class).getAll().stream().filter(s->dockerIds.contains(s.getId())).collect(Collectors.toList());
        Map<String, List<Container>> containerMap = SpringUtils.getBean(AdmDockerServiceImpl.class).getContainerMap(dockerList);
        voList.forEach(vo -> {
            AdmDocker admDocker = dockerList.stream().filter(s -> s.getId().equals(vo.getDockerId())).findFirst().orElse(null);
            if (admDocker == null){
                vo.setStateName("未绑定docker");
            }else {
                List<Container> containers = containerMap.get("AdmDockerVo" + admDocker.getId());
                Container container = containers.stream().filter(s -> s.getId().equals(vo.getContainerId())).findFirst().orElse(null);
                if (container == null) {
                    vo.setStateName("未创建或超时");
                } else {
                    vo.setStateName(container.getState());
                }
                Server server = serverList.stream().filter(s -> s.getId().equals(admDocker.getServerId())).findFirst().orElse(null);
                vo.setIp(server.getIp());
                vo.setServerId(server.getId());
            }
        });
        return voList;

    }

    @Override
    public void install(String ids, String tempPath, MultipartFile nginxFile) {
        long fileSize = nginxFile.getSize();
        String[] split = ids.split(",");
        CountDownLatch mainLatch = new CountDownLatch(split.length);
        for (String id : split) {
            threadPoolTaskExecutor.execute(() -> {
                //上传包
                try {
                    AdmNginx nginx = admNginxMapper.selectById(id);
                    String mountPath = nginx.getMountPath();
                    if (nginx.getDockerId() == null) {
                        return;
                    }
                    AdmDocker admDocker = admDockerMapper.selectById(nginx.getDockerId());
                    Server serverDocker = serverService.getServerById(nginx.getServerId());
                    Session session = remoteSshUtil.connect(serverDocker);
                    System.out.println("开始上传nginx镜像文件");
                    //关闭防火墙
                    remoteSshUtil.exec(AutoConstants.DISABLE_FIREWALLD, session);
                    remoteSshUtil.exec(AutoConstants.STOP_FIREWALLD, session);
                    remoteSshUtil.exec(AutoConstants.AUTHORIZATION_FOLDER + tempPath, session);
                    remoteSshUtil.exec(StringUtils.format("mkdir -p {}/conf {}/log  {}/html",mountPath,mountPath,mountPath), session);
                    CountDownLatch mainLatch2 = new CountDownLatch(1);
                    threadPoolTaskExecutor.execute(() -> {
                        try {
                            remoteSshUtil.putFile(session, nginxFile, tempPath, fileSize, Long.parseLong(id), "ngInstall",serverDocker.getIp());
                        } catch (Exception e) {
                            throw new ServiceException(e.getMessage());
                        } finally {
                            mainLatch2.countDown();
                        }
                    });
                    mainLatch2.await();
                    sendMsg("installing", nginxFile.getOriginalFilename(), Long.parseLong(id));
                    DockerClient dockerClient = dockerUtil.getDockerClientByDocker(SpringUtils.getBean(AdmDockerServiceImpl.class).convertToVo(admDocker));
                    dockerUtil.delContainer(dockerClient, "nginx");
                    sendMsg("loading", nginxFile.getOriginalFilename(), Long.parseLong(id));
                    //加载到镜像
                    remoteSshUtil.exec(StringUtils.format("docker load -i {}/{}", tempPath, nginxFile.getOriginalFilename()), session);
                    remoteSshUtil.exec("docker run --name nginx -p 80:80 -d nginx", session);
                    remoteSshUtil.exec(StringUtils.format("docker cp nginx:/etc/nginx/nginx.conf {}/conf/nginx.conf",mountPath), session);
                    remoteSshUtil.exec(StringUtils.format("docker cp nginx:/etc/nginx/conf.d {}/conf/conf.d",mountPath), session);
                    remoteSshUtil.exec(StringUtils.format("docker cp nginx:/usr/share/nginx/html {}/",mountPath), session);
                    dockerUtil.delContainer(dockerClient, "nginx");
                    //安装mysql
                    String info = StringUtils.format("docker run \\\n" +
                            "--restart=always \\\n" +
                            "--privileged=true \\\n" +
                            "--net host \\\n" +
                            "--name nginx \\\n" +
                            "-v {}/conf/nginx.conf:/etc/nginx/nginx.conf \\\n" +
                            "-v {}/conf/conf.d:/etc/nginx/conf.d \\\n" +
                            "-v {}/log:/var/log/nginx \\\n" +
                            "-v {}/html:/usr/share/nginx/html \\\n" +
                            "-v /etc/localtime:/etc/localtime \\\n" +
                            "-d nginx:latest", mountPath, mountPath, mountPath, mountPath);
                    System.out.println(info);
                    String exec = remoteSshUtil.exec(info, session);
                    System.out.println(exec);
                    nginx.setContainerId(exec.replace("\n", ""));
                    nginx.setInstallTime(new Date());
                    this.updateById(nginx);
                    sendMsg("complete", nginxFile.getOriginalFilename(), Long.parseLong(id));
                    remoteSshUtil.close(session);
                    dockerUtil.close(dockerClient);
                } catch (Exception e) {
                    e.printStackTrace();
                    alertFailMsg(e.getMessage());
                } finally {
                    mainLatch.countDown();
                }
            });
        }
        try {
            mainLatch.await();
            System.out.println("ng全部安装完毕");
            alertSuccessMsg("completeAll");
        } catch (InterruptedException e) {
            log.error(e.getMessage());
        }
    }

    @Override
    public void restartService(String ids) {
        String[] split = ids.split(",");
        List<String> strings = Arrays.asList(split);
        List<AdmNginx> list = admNginxMapper.selectBatchIds(strings);
        for (AdmNginx nginx : list) {
            AdmDocker admDocker = admDockerMapper.selectById(nginx.getDockerId());
            DockerClient dockerClient = dockerUtil.getDockerClientByDocker(SpringUtils.getBean(AdmDockerServiceImpl.class).convertToVo(admDocker));
            dockerClient.restartContainerCmd(nginx.getContainerId()).exec();
            dockerUtil.close(dockerClient);
            log.info("重启成功:{}", JacksonUtils.toString(nginx));
        }
    }


    private void sendMsg(String status, String name, Long id) {
        websocketEndPoint.send(WsSendDto.builder().type(0).table("ngInstall").status(status).name(name).id(id).build());
    }

    /**
     * 弹窗提示
     *
     * @param data
     */
    private void alertSuccessMsg(String data) {
        websocketEndPoint.send(WsSendDto.builder().type(2).table("ngInstall").data(data).build());
    }

    /**
     * 弹窗提示
     *
     * @param data
     */
    private void alertFailMsg(String data) {
        websocketEndPoint.send(WsSendDto.builder().type(3).table("ngInstall").data(data).build());
    }
}
